package pers.cz.pub;

import cn.hutool.core.date.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pers.cz.mapper.SequenceMapper;
import pers.cz.model.Sequence;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 封装常用的公共方法
 * @program: PostGirl-panent
 * @description: CpublicFunc
 * @author: Cheng Zhi
 * @create: 2021-03-12 12:44
 **/
public class CpublicFunc {

    Logger logger = LoggerFactory.getLogger(CpublicFunc.class);

    private BeanHelper daoHelper;

    private static Map<String, Long[]> sequenceMap; // list中保存两个数，第一个为当前值，第二个为缓存大小

    static {
        sequenceMap = new ConcurrentHashMap<String, Long[]>();
    }
    public CpublicFunc() {
    }

    public CpublicFunc(BeanHelper daoHelper) {
        this.daoHelper = daoHelper;
    }

    /**
     * 获取公共so_nbr
     * @return
     */
    public synchronized Long getSoNbr() {
        String sequenceName = "PUBLIC_SEQUENCE";
        return querySequence(sequenceName);
    }

    /**
     * 获取指定sequence的so_nbr,
     * @param sequence
     * @return
     */
    private synchronized Long getSoNbr(String sequence) {
        return querySequence(sequence);
    }

    public Long getSoNbr(SequenceEnum sequenceEnum) {

        return getSoNbr(sequenceEnum.getValue());
    }
    /**
     * 查询sequence获取so_nbr
     * @param sequenceName
     * @return
     */
    private Long querySequence(String sequenceName) {

        long soNbr = 0L;
        long newSoNbr = 0L;
        long limit = 0L;

        // 先尝试从缓存中获取，如果缓存中没有再进行查询
        Long[] queue = sequenceMap.get(sequenceName);
        if (queue != null) {

            long cacheSize = queue[1];
            if (cacheSize > 0) {
                soNbr = queue[0] + 1;
                cacheSize --;
                queue[0] = soNbr;
                queue[1] = cacheSize;
                sequenceMap.put(sequenceName, queue);
                return soNbr;
            }
        }

        synchronized (this) {

            // 1、获取事务管理器
            DataSourceTransactionManager bean = (DataSourceTransactionManager) daoHelper.getSpringBean("dataSourceTransactionManager");
            // 2、获取事务定义
            DefaultTransactionDefinition def = new DefaultTransactionDefinition();
            // 3、设置事务传播行为，开启新事务
            def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
            TransactionStatus transaction = bean.getTransaction(def);

            try {
                Sequence sequence = new Sequence();
                // 在sql添加一个随机数用来破坏mybatis一级缓存的缓存机制
                double random = Math.random();
                sequence = daoHelper.getBean(SequenceMapper.class).selectByPrimaryKey(sequenceName, random + "");
                soNbr = sequence.getSequenceValue();
                limit = sequence.getInitLimit();
                newSoNbr = soNbr + limit + 1; // +1的目的是为了缓存获取sequence_value没有从0开始，都是从1开始的。
                sequence.setSequenceValue(newSoNbr);
                sequence.setUpdateDate(DateUtil.date());
                SequenceMapper bean1 = daoHelper.getBean(SequenceMapper.class);
                bean1.updateByPrimaryKeySelective(sequence);
                bean.commit(transaction);
                Long[] entity = new Long[2];
                entity[0] = soNbr;
                entity[1] = limit;
                sequenceMap.put(sequenceName, entity);
            } catch (Exception e) {
                bean.rollback(transaction);
                logger.error("get sequence error", e);
            }
        }
        return soNbr;
    }
}
